package com.youlu.campus.service.auth.impl;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import com.mongodb.client.result.UpdateResult;
import com.youlu.campus.base.exception.BusinessException;
import com.youlu.campus.base.user.WechatLogoAuth;
import com.youlu.campus.common.exception.WechatException;

import com.youlu.campus.component.QiniuUtil;
import com.youlu.campus.entity.PlatformConfig;
import com.youlu.campus.entity.SystemApolloConfig;
import com.youlu.campus.entity.SystemNickNameAndHeaderImage;
import com.youlu.campus.entity.UserOtherInfo;
import com.youlu.campus.entity.VO.res.UserResponse;
import com.youlu.campus.entity.WechatH5UserPO;
import com.youlu.campus.entity.domain.WechatAccessToken;
import com.youlu.campus.service.auth.WechatH5UserService;
import com.youlu.campus.service.cache.CacheUserService;
import com.youlu.campus.service.platform.PlatformConfigService;
import com.youlu.campus.service.system.SystemApolloConfigService;
import com.youlu.campus.service.wechat.SystemNickNameAndHeaderImageService;
import lombok.extern.slf4j.Slf4j;
import net.polyv.live.util.HttpClientUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Objects;


@Slf4j
@Service
public class WechatH5UserServiceImpl implements WechatH5UserService {

    @Lazy
    @Autowired
    private CacheUserService cacheUserService;

    @Autowired
    private MongoTemplate mongoTemplate;
    @Autowired
    private SystemNickNameAndHeaderImageService systemNickNameAndHeaderImageService;
    @Autowired
    private PlatformConfigService platformConfigService;

    @Autowired
    private QiniuUtil qiniuUtil;
    @Autowired
    private SystemApolloConfigService systemApolloConfigService;

    @Override
    public WechatH5UserPO findByOpenId(String openId, String appId) {
        log.info(":>>> 开始查询微信H5用户 openId:{},appId:{}", openId, appId);
        if (StringUtils.isBlank(openId)) {
            log.error(":>>> openId 为空:{}", openId);
            throw new BusinessException("参数错误:openId为空");
        }
        return cacheUserService.findByOpenId(appId, openId);
    }

    @Async
    @Override
    public void updateAccountId(String openid, String userId, String accountUserId) {
        Query query = new Query().addCriteria(Criteria.where("id").is(userId));
        Update update = new Update();
        update.set("accountInfoId", accountUserId);
        mongoTemplate.updateFirst(query, update, WechatH5UserPO.class);
        cacheUserService.removeWechatH5UserOpenId(openid);
        log.info(":>>> 用户:{},账户信息不存在:{},更新账号信息", openid, userId);
    }

    @Async
    @Override
    public void updateByOpenId(String openId, WechatAccessToken info) {
        if (Objects.isNull(info)) {
            return;
        }
        log.info("用户登录->{} 更新地址信息", openId);
        Query query1 = new Query().addCriteria(Criteria.where("openId").is(info.getOpenId()));
        Update update = new Update();
        if (StringUtils.isNotBlank(info.getHeadimgurl())) {
            String url = info.getHeadimgurl().replace("\\", "");
            log.info(":>>> 解析后的头像:{}", url);
            update.set("avatarUrl", url);
        }
        if (StringUtils.isNotBlank(info.getNickName())) {
            update.set("nickName", info.getNickName());
        }
        if (StringUtils.isNotBlank(info.getProvince())) {
            update.set("province", info.getProvince());
        }
        if (StringUtils.isNotBlank(info.getCity())) {
            update.set("city", info.getCity());
        }
        if (Objects.nonNull(info.getSex())) {
            update.set("gender", info.getSex());
        }
        if (Objects.nonNull(info.getNickImageType())) {
            update.set("nickImageType", info.getNickImageType());
        }
        mongoTemplate.updateFirst(query1, update, WechatH5UserPO.class);
        this.cacheUserService.removeWechatH5UserOpenId(openId);
    }

    @Async
    @Override
    public void updateById(String id, WechatAccessToken info) {
        if (Objects.isNull(info)) {
            return;
        }
        log.info("用户登录->{} 更新地址信息", info.getOpenId());
        Query query1;
        if (StringUtils.isNotBlank(id)) {
            query1 = new Query().addCriteria(Criteria.where("id").is(id));
            ;
        } else {
            query1 = new Query().addCriteria(Criteria.where("openId").is(info.getOpenId()));
        }
        Update update = new Update();
        if (StringUtils.isNotBlank(info.getHeadimgurl())) {
            String url = info.getHeadimgurl().replace("\\", "");
            log.info(":>>> 解析后的头像:{}", url);
            update.set("avatarUrl", url);
        }
        if (StringUtils.isNotBlank(info.getNickName())) {
            update.set("nickName", info.getNickName());
        }
        if (StringUtils.isNotBlank(info.getProvince())) {
            update.set("province", info.getProvince());
        }
        if (StringUtils.isNotBlank(info.getCity())) {
            update.set("city", info.getCity());
        }
        if (Objects.nonNull(info.getSex())) {
            update.set("gender", info.getSex());
        }
        if (Objects.nonNull(info.getNickImageType())) {
            update.set("nickImageType", info.getNickImageType());
        }
        update.set("validLogo", info.getValidLogo());
        mongoTemplate.updateFirst(query1, update, WechatH5UserPO.class);
        this.cacheUserService.removeWechatH5UserOpenId(info.getOpenId());
    }

    @Async
    @Override
    public void updateOtherInfo(UserOtherInfo u) {
        if (Objects.isNull(u) || StringUtils.isBlank(u.getUserId())) {
            log.error(":>>> 修改用户其他信息参数错误");
            return;
        }
        Query query = new Query().addCriteria(Criteria.where("accountInfoId").is(u.getUserId()));
        Update up = new Update();
        boolean doIt = false;
        if (StringUtils.isNotBlank(u.getNickName())) {
            up.set("nickName", u.getNickName());
            doIt = true;
        }
        if (StringUtils.isNotBlank(u.getAvatarUrl())) {
            up.set("avatarUrl", u.getAvatarUrl());
            doIt = true;
        }
        if (doIt) {
            up.set("updatedTime", new Date());
            UpdateResult updateResult = mongoTemplate.updateMulti(query, up, WechatH5UserPO.class);
            log.info(":>>> 修改微信H5用户信息结果:{},{}", u.getUserId(), updateResult.getModifiedCount());
        }

    }

    @Override
    public UserResponse getUserInfo(String accessToken, String openId, String id) {
        log.info(":>>> 开始获取用户信息:{},{}", accessToken, openId);
        UserResponse userResponse = null;
        String way = "1";
        PlatformConfig platformConfig = platformConfigService.find();
        if (Objects.nonNull(platformConfig)) {
            way = platformConfig.getUserInfoGetWay();
        }
        switch (way) {
            case "1":
                userResponse = this.getUserInfoFromWechat(accessToken, openId, id);
                if (Objects.isNull(userResponse) || (StringUtils.isBlank(userResponse.getAvatarUrl()) || StringUtils.isBlank(userResponse.getNickName()))) {
                    log.info(":>>> 从微信获取头像错误,从本地默认获取");
                    userResponse = this.getUserInfoDefealt(openId);
                }
                break;
            case "2":
                userResponse = this.getUserInfoDefealt(openId);
                break;
            default:
                break;
        }
        return userResponse;
    }

    @Override
    public List<WechatH5UserPO> getWechatUserList(Collection<String> accountIdList) {
        if (CollectionUtils.isEmpty(accountIdList)) {
            return Collections.emptyList();
        }
        return mongoTemplate.find(new Query(Criteria.where("accountInfoId").in(accountIdList)), WechatH5UserPO.class);
    }

    /**
     * 从微信获取用户信息
     *
     * @param accessToken
     * @param openId
     * @return
     */
    UserResponse getUserInfoFromWechat(String accessToken, String openId, String id) {
        final String urlInfo = "https://api.weixin.qq.com/sns/userinfo";
        UserResponse userResponse = new UserResponse();
        try {
            String infoObj =
                    HttpClientUtil.getInstance().sendHttpGet(urlInfo + "?access_token=" + accessToken + "&openid=" + openId + "&lang=zh_CN");
            log.info(":>>> H5获取的用户昵称等信息为:{}", infoObj);
            if (StringUtils.isNotBlank(infoObj)) {
                WechatAccessToken info = JSON.parseObject(infoObj, WechatAccessToken.class);
                log.info(":>>> 返回的用户信息:{}", JSON.toJSONString(info));
                if (info != null) {
                    userResponse.setAvatarUrl(info.getHeadimgurl());
                    userResponse.setNickName(info.getNickName());
                }
                if (Objects.nonNull(info) && (StringUtils.isNotBlank(info.getHeadimgurl()) && StringUtils.isNotBlank(info.getNickName()))) {
                    log.info(":>>> 微信头像和昵称可以获取到");
                    // 更新上传头像到七牛
                    String uploadUrl = qiniuUtil.uploadFileByUrl(info.getHeadimgurl(), "", "wechat-", false, null);
                    List<String> contents = Lists.newArrayList("1", "2");
                    if (!contents.contains(uploadUrl)) {
                        userResponse.setAvatarUrl(uploadUrl);
                        info.setHeadimgurl(uploadUrl);
                    } else {
                        userResponse.setAvatarUrl(info.getHeadimgurl());
                    }
                    userResponse.setNickName(info.getNickName());
                    info.setOpenId(openId);
                    info.setValidLogo(true);
                    info.setNickImageType("1");
                    this.updateById(id, info);
                }
            }
        } catch (Exception e) {
            log.error(":>>> 获取用户信息错误:{}", e);
        }
        return userResponse;

    }

    /**
     * 获取系统默认用户信息
     *
     * @param openId
     * @return
     */
    UserResponse getUserInfoDefealt(String openId) {
        log.info(":>>> 微信头像和昵称设置为系统默认");
        UserResponse userResponse = new UserResponse();
        SystemNickNameAndHeaderImage system = systemNickNameAndHeaderImageService.getRandom();
        log.info(":>>> 系统默认的头像和昵称ID:{}", system == null ? null : system.getId());
        if (Objects.nonNull(system)) {
            userResponse.setAvatarUrl(system.getAvatarUrl());
            userResponse.setNickName(system.getNickName());
            WechatAccessToken info = new WechatAccessToken();
            info.setHeadimgurl(system.getAvatarUrl());
            info.setNickName(system.getNickName());
            info.setOpenId(openId);
            info.setNickImageType("2");
            this.updateByOpenId(openId, info);
        } else {
            log.error(":>>> 微信头像和昵称无法获取到,系统默认头像无法获取,严重告警");
        }
        return userResponse;

    }

    @Override
    public void uploadH5WechatPic(WechatH5UserPO wechatH5UserPO) {
        String url = wechatH5UserPO.getAvatarUrl();
        if (StringUtils.isBlank(url) || !url.startsWith("https://thirdwx.qlogo.cn")) {
            return;
        }
//        Config config = ConfigService.getAppConfig();
//        String cnf = config.getProperty("wechat.logo.auth.gray", "{}");
//        WechatLogoAuth wechatLogoAuth = JSON.parseObject(cnf,WechatLogoAuth.class);
        SystemApolloConfig systemApolloConfig = systemApolloConfigService.find();
        WechatLogoAuth wechatLogoAuth = systemApolloConfig.getWechatLogoAuth();
        // 是否开启更新头像
        if (!wechatLogoAuth.getUpdateLogoOpened()) {
            return;
        }
        List<String> whiteList = wechatLogoAuth.getUserList();
        boolean reLogin = wechatLogoAuth.getAuthOpened() && CollectionUtils.isNotEmpty(whiteList) && (whiteList.contains("*") || whiteList.contains(wechatH5UserPO.getId()));
        if (wechatH5UserPO.getValidLogo() != null && !wechatH5UserPO.getValidLogo()) {
            if (reLogin) {
                throw new WechatException(110, "用户未登陆");
            }
            return;
        }
        List<String> contents = Lists.newArrayList("1", "2");
        // 更新用户需要校验图片
        String uploadUrl = qiniuUtil.uploadFileByUrl(url, "", "wechat-", true, wechatLogoAuth.getLogoMd5List());
        if (!contents.contains(uploadUrl)) {
            updateUser(wechatH5UserPO, uploadUrl, true);
            return;
        }
        // 上传失败不处理
        if ("2".equals(uploadUrl)) {
            log.info("uploadH5WechatPic fail openId:{}, id :{}", wechatH5UserPO.getOpenId(), wechatH5UserPO.getId());
            return;
        }
        // 更新无效状态
        updateUser(wechatH5UserPO, uploadUrl, false);
        log.info("uploadH5WechatPic pic is expire, id:{},openId:{}", wechatH5UserPO.getId(), wechatH5UserPO.getOpenId());
        if (reLogin) {
            log.info("uploadH5WechatPic in white list userId need relogin:{},openId:{}", wechatH5UserPO.getId(), wechatH5UserPO.getOpenId());
            throw new WechatException(110, "用户未登陆");
        }
    }

    public void updateUser(WechatH5UserPO wechatH5UserPO, String uploadUrl, boolean up) {
        Query query = new Query(Criteria.where("id").is(wechatH5UserPO.getId()));
        Update update = new Update();
        if (up) {
            update.set("avatarUrl", uploadUrl);
            update.set("validLogo", true);
            wechatH5UserPO.setAvatarUrl(uploadUrl);
        } else {
            update.set("validLogo", false);
            wechatH5UserPO.setValidLogo(false);
        }
        // 删除缓存
        cacheUserService.removeWechatH5UserOpenId(wechatH5UserPO.getOpenId());
        // 更新头像
        mongoTemplate.updateFirst(query, update, WechatH5UserPO.class);
    }

    @Override
    public WechatH5UserPO findByAccountInfoId(String userId) {
        Query query = new Query(Criteria.where("accountInfoId").is(userId));
        List<WechatH5UserPO> wechatH5UserPOS = mongoTemplate.find(query, WechatH5UserPO.class);
        return wechatH5UserPOS == null ? null : wechatH5UserPOS.get(0);
    }
}
